# LuckPay Web Manage System
#
# Copyright (c) 2016 Lucky Byte, Inc.
#
sched   = require 'node-schedule'
pgsql   = require 'pg'
moment  = require 'moment'
uuid    = require 'uuid'

jobs = {}
module.exports = jobs


send_notify = (message, detail, level) ->
    await pgsql.connect settings.pgsql_url, defer err, client, done
    return done(client) and console.log(err) if err

    await client.query "insert into web_notify (
            sender, message, detail, level
        ) values (
            $1, $2, $3, $4
        )", [
        1, message, detail, level
    ], defer err, result
    return done(client) and console.log(err) if err
    done()


# 商户复核后生效
take_merch_effect = (merch_uuid) ->
    await pgsql.connect settings.pgsql_url, defer err, client, done
    return done(client) and console.log(err) if err

    client.query "begin"
    await client.query \
        "select * from pay_merch_ex where uuid = $1 for update", [
            merch_uuid
        ], defer err, result
    return done(client) and console.log(err) if err

    if result.rows.length == 0
        client.query "rollback;"
        return done(client) and console.log(err) if err
        done()
        return console.log '未找到待生效的商户记录'

    record = result.rows[0]

    # 执行这里可能已经离复核有一段时间了，因此需要重新检查记录状态
    if record.rejected
        client.query "rollback"
        done()
        return console.log '商户信息复核时被拒绝，不能生效'
    if not record.checked
        client.query "rollback"
        done()
        return console.log '商户信息尚未复核，不能生效'

    switch record.action
        when 1, 2      # 新增/修改商户信息
            await client.query "update pay_merch set
                    inside = $1,             chnl = $2,             merno = $3,
                    trctl = $4,              settl_merid = $5,      mapto_merid = $6,
                    name = $7,               contact = $8,          telephone = $9,
                    mobile = $10,            fax = $11,             email = $12,
                    address = $13,
                    unit_name = $14,         unit_name_abbr = $15,  unit_english = $16,
                    unit_english_abbr = $17, unit_code = $18,       unit_license = $19,
                    unit_license_exp = $20,  unit_tax_code = $21,   unit_issuer = $22,
                    unit_address = $23,      unit_type = $24,       unit_legal_name = $25,
                    unit_cred_type = $26,    unit_cred_no = $27,    unit_assets = $28,
                    unit_scope = $29,
                    keys = $30,              notes = $31,
                    inputer = $32,           input_time = $33,
                    checker = $34,           check_time = $35,
                    effect_time = $36,       shaded = false,        t20_fee = $37
                where uuid = $38", [
                    record.inside, record.chnl, record.merno,
                    record.trctl,  record.settl_merid, record.mapto_merid,
                    record.name, record.contact, record.telephone,
                    record.mobile, record.fax, record.email, record.address,
                    record.unit_name, record.unit_name_abbr, record.unit_english,
                    record.unit_english_abbr, record.unit_code, record.unit_license,
                    record.unit_license_exp, record.unit_tax_code, record.unit_issuer,
                    record.unit_address, record.unit_type, record.unit_legal_name,
                    record.unit_cred_type, record.unit_cred_no, record.unit_assets,
                    record.unit_scope,
                    record.keys, record.notes,
                    record.inputer, record.input_time,
                    record.checker, record.check_time, record.effect_time,
                    record.t20_fee,
                    record.ref_uuid
                ], defer err, result
            if err
                console.error err.message
                console.error err.detail if err.detail
                client.query "rollback"
                done()

                # 如果更新失败，则调度一分钟后重试
                return sched.scheduleJob moment().add('1', 'm').toDate(), ->
                    take_merch_effect merch_uuid
            else
                # 同时删除复核表中记录
                await client.query "delete from pay_merch_ex where uuid = $1", [
                    merch_uuid ], defer err, result
                client.query "commit"
                return done()
        when 3      # 删除
            # 删除复核表中记录
            await client.query "delete from pay_merch_ex where uuid = $1", [
                    merch_uuid
                ], defer err, result

            # 尝试删除，如果没有外键引用，则删除之
            await client.query \
                "delete from pay_merch where uuid = $1", [
                    record.ref_uuid
                ], defer err, result
            if err
                console.error  err.message
                console.error err.detail if err.detail
                client.query "rollback"
                done()

                # 如果删除失败，则调度一分钟后重新删除
                sched.scheduleJob moment().add('1', 'm').toDate(), ->
                    take_merch_effect merch_uuid
            else
                client.query "commit"
                return done()
        else  # action 无效
            send_notify '系统错误', "复核表中 action 无效，UUID = #{merch_uuid}", 4


# 增加调度器，让复核后的商户信息生效
jobs.sched_effect = (merch_uuid, effect_time) ->
    if typeof effect_time is 'string'
        effect_time = moment(effect_time)
    # 如果时间早于未来的一分钟，则直接生效
    if effect_time.isBefore(moment().add('1', 'm'))
        take_merch_effect merch_uuid
    else
        sched.scheduleJob effect_time.toDate(), ->
            take_merch_effect merch_uuid


# 启动时调用此函数注册所有的定时任务
# 注意，如果同时启动多个 NodeJS 服务器，那么每个服务器都注册调度器的话，
# 会浪费资源，同时会有冲突，因此请设置一个主服务器，参考 etc/settings.js
jobs.add_all = ->
    await pgsql.connect settings.pgsql_url, defer err, client, done
    return done(client) and next err if err

    # 复核后待生效商户
    await client.query \
        "select * from pay_merch_ex where checked = true", defer err, result
    return done(client) and next err if err
    done()

    for record in result.rows
        jobs.sched_effect record.uuid, record.effect_time
